﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.RoamingStoreFileUtility
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.InfoCards
{
  internal sealed class RoamingStoreFileUtility
  {
    private static readonly byte[] DerivedKeySignatureEntropy = new byte[16]
    {
      (byte) 196,
      (byte) 1,
      (byte) 123,
      (byte) 241,
      (byte) 107,
      (byte) 173,
      (byte) 47,
      (byte) 66,
      (byte) 175,
      (byte) 244,
      (byte) 151,
      (byte) 125,
      (byte) 4,
      (byte) 104,
      (byte) 3,
      (byte) 219
    };
    private static readonly byte[] DerivedKeyEncryptionEntropy = new byte[16]
    {
      (byte) 217,
      (byte) 89,
      (byte) 123,
      (byte) 38,
      (byte) 30,
      (byte) 216,
      (byte) 179,
      (byte) 68,
      (byte) 147,
      (byte) 35,
      (byte) 179,
      (byte) 150,
      (byte) 133,
      (byte) 222,
      (byte) 149,
      (byte) 252
    };
    private const int ENCRYPTIONKEYBUFFERSIZE = 32;
    private const int ENCRYPTIONKEYBITLENGTH = 256;
    private const int ENCRYPTIONIVBUFFERSIZE = 16;
    private const int ENCRYPTIONIVBITLENGTH = 128;
    private const int ITERATIONCOUNT = 1000;
    private const int SHA256_BUFFERSIZE = 32;

    public static int SaltLength
    {
      get
      {
        return 16;
      }
    }

    private RoamingStoreFileUtility()
    {
    }

    public static int CalculateEncryptedSize(int decryptedLength)
    {
      int num = decryptedLength;
      return num + (16 - num % 16) + 48;
    }

    public static int CalculateDecryptedSize(int encryptedLength)
    {
      return encryptedLength - 48;
    }

    public static void Decrypt(
      Stream source,
      Stream destination,
      string passwordString,
      byte[] salt)
    {
      byte[] bytes = Encoding.Unicode.GetBytes(passwordString);
      byte[] encryptionKey;
      byte[] signatureKey;
      try
      {
        RoamingStoreFileUtility.CreateKeyPair(bytes, salt, out encryptionKey, out signatureKey);
      }
      finally
      {
        Array.Clear((Array) bytes, 0, bytes.Length);
      }
      try
      {
        byte[] numArray1 = new byte[16];
        if (numArray1.Length != source.Read(numArray1, 0, numArray1.Length))
          throw InfoCardTrace.ThrowHelperError((Exception) new ImportException(SR.GetString("InvalidImportFile")));
        using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
        {
          rijndaelManaged.Padding = PaddingMode.PKCS7;
          rijndaelManaged.Mode = CipherMode.CBC;
          rijndaelManaged.BlockSize = numArray1.Length * 8;
          rijndaelManaged.KeySize = encryptionKey.Length * 8;
          using (RijndaelManagedTransform decryptor = (RijndaelManagedTransform) rijndaelManaged.CreateDecryptor(encryptionKey, numArray1))
          {
            using (SHA256Managed shA256Managed = new SHA256Managed())
            {
              byte[] numArray2 = new byte[decryptor.InputBlockSize];
              byte[] numArray3 = new byte[decryptor.OutputBlockSize];
              byte[] numArray4 = new byte[shA256Managed.HashSize / 8];
              using (MemoryStream memoryStream = new MemoryStream(new byte[numArray1.Length + encryptionKey.Length + decryptor.OutputBlockSize]))
              {
                if (numArray4.Length != source.Read(numArray4, 0, numArray4.Length))
                  throw InfoCardTrace.ThrowHelperError((Exception) new ImportException(SR.GetString("InvalidImportFile")));
                memoryStream.Write(numArray1, 0, numArray1.Length);
                memoryStream.Write(signatureKey, 0, signatureKey.Length);
                while (source.Position < source.Length - (long) numArray2.Length)
                {
                  try
                  {
                    int inputCount = source.Read(numArray2, 0, numArray2.Length);
                    int count = decryptor.TransformBlock(numArray2, 0, inputCount, numArray3, 0);
                    if (count > 0)
                      destination.Write(numArray3, 0, count);
                  }
                  finally
                  {
                    Array.Clear((Array) numArray3, 0, numArray3.Length);
                    Array.Clear((Array) numArray2, 0, numArray2.Length);
                  }
                }
                int inputCount1 = source.Read(numArray2, 0, numArray2.Length);
                byte[] buffer = decryptor.TransformFinalBlock(numArray2, 0, inputCount1);
                destination.Write(buffer, 0, buffer.Length);
                memoryStream.Write(buffer, buffer.Length - decryptor.OutputBlockSize, decryptor.OutputBlockSize);
                memoryStream.Flush();
                memoryStream.Seek(0L, SeekOrigin.Begin);
                if (!RoamingStoreFileUtility.CompareSignature(shA256Managed.ComputeHash((Stream) memoryStream), numArray4))
                  throw InfoCardTrace.ThrowHelperError((Exception) new ImportException(SR.GetString("InvalidImportFile")));
              }
            }
          }
        }
      }
      finally
      {
        Array.Clear((Array) encryptionKey, 0, encryptionKey.Length);
        Array.Clear((Array) signatureKey, 0, signatureKey.Length);
      }
    }

    public static void Encrypt(
      Stream source,
      Stream destination,
      string passwordString,
      out byte[] salt)
    {
      RandomNumberGenerator randomNumberGenerator = (RandomNumberGenerator) new RNGCryptoServiceProvider();
      salt = new byte[16];
      randomNumberGenerator.GetBytes(salt);
      byte[] bytes = Encoding.Unicode.GetBytes(passwordString);
      byte[] encryptionKey;
      byte[] signatureKey;
      try
      {
        RoamingStoreFileUtility.CreateKeyPair(bytes, salt, out encryptionKey, out signatureKey);
      }
      finally
      {
        Array.Clear((Array) bytes, 0, bytes.Length);
      }
      try
      {
        byte[] numArray1 = new byte[16];
        randomNumberGenerator.GetBytes(numArray1);
        using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
        {
          rijndaelManaged.Padding = PaddingMode.PKCS7;
          rijndaelManaged.Mode = CipherMode.CBC;
          rijndaelManaged.BlockSize = numArray1.Length * 8;
          rijndaelManaged.KeySize = encryptionKey.Length * 8;
          using (RijndaelManagedTransform encryptor = (RijndaelManagedTransform) rijndaelManaged.CreateEncryptor(encryptionKey, numArray1))
          {
            using (SHA256Managed shA256Managed = new SHA256Managed())
            {
              byte[] numArray2 = new byte[encryptor.InputBlockSize];
              byte[] buffer1 = (byte[]) null;
              byte[] numArray3 = new byte[encryptor.OutputBlockSize];
              byte[] buffer2 = new byte[numArray1.Length + shA256Managed.HashSize / 8];
              using (MemoryStream memoryStream = new MemoryStream(new byte[numArray1.Length + signatureKey.Length + encryptor.InputBlockSize]))
              {
                memoryStream.Write(numArray1, 0, numArray1.Length);
                memoryStream.Write(signatureKey, 0, signatureKey.Length);
                try
                {
                  destination.Write(buffer2, 0, buffer2.Length);
                  int num = 0;
                  while (source.Position < source.Length - (long) numArray2.Length)
                  {
                    num = source.Read(numArray2, 0, numArray2.Length);
                    try
                    {
                      int count = encryptor.TransformBlock(numArray2, 0, numArray2.Length, numArray3, 0);
                      destination.Write(numArray3, 0, count);
                    }
                    finally
                    {
                      Array.Clear((Array) numArray2, 0, numArray2.Length);
                      Array.Clear((Array) numArray3, 0, numArray3.Length);
                    }
                  }
                  int inputCount = source.Read(numArray2, 0, numArray2.Length);
                  if (inputCount != numArray2.Length)
                  {
                    byte[] buffer3 = new byte[numArray2.Length];
                    source.Seek(source.Length - (long) numArray2.Length, SeekOrigin.Begin);
                    InfoCardTrace.Assert(source.Read(buffer3, 0, buffer3.Length) == buffer3.Length && buffer3.Length == numArray2.Length, "Should have read exactly 0x20 bytes");
                    memoryStream.Write(buffer3, 0, buffer3.Length);
                  }
                  else
                    memoryStream.Write(numArray2, 0, numArray2.Length);
                  buffer1 = encryptor.TransformFinalBlock(numArray2, 0, inputCount);
                  destination.Write(buffer1, 0, buffer1.Length);
                  destination.Flush();
                  memoryStream.Flush();
                  memoryStream.Seek(0L, SeekOrigin.Begin);
                  byte[] hash = shA256Managed.ComputeHash((Stream) memoryStream);
                  Array.Copy((Array) numArray1, 0, (Array) buffer2, 0, numArray1.Length);
                  Array.Copy((Array) hash, 0, (Array) buffer2, numArray1.Length, hash.Length);
                  destination.Seek(0L, SeekOrigin.Begin);
                  destination.Write(buffer2, 0, buffer2.Length);
                  destination.Flush();
                  destination.Seek(0L, SeekOrigin.End);
                }
                finally
                {
                  Array.Clear((Array) numArray2, 0, numArray2.Length);
                  Array.Clear((Array) numArray3, 0, numArray3.Length);
                  Array.Clear((Array) buffer2, 0, buffer2.Length);
                  if (buffer1 != null)
                    Array.Clear((Array) buffer1, 0, buffer1.Length);
                }
              }
            }
          }
        }
      }
      finally
      {
        Array.Clear((Array) encryptionKey, 0, encryptionKey.Length);
        Array.Clear((Array) signatureKey, 0, signatureKey.Length);
      }
    }

    private static void CreateKeyPair(
      byte[] password,
      byte[] salt,
      out byte[] encryptionKey,
      out byte[] signatureKey)
    {
      byte[] numArray = RoamingStoreFileUtility.DoPkcs5(password, salt);
      using (SHA256Managed shA256Managed = new SHA256Managed())
      {
        byte[] buffer1 = new byte[32 + RoamingStoreFileUtility.DerivedKeyEncryptionEntropy.Length];
        byte[] buffer2 = new byte[32 + RoamingStoreFileUtility.DerivedKeySignatureEntropy.Length];
        Array.Copy((Array) RoamingStoreFileUtility.DerivedKeyEncryptionEntropy, 0, (Array) buffer1, 0, RoamingStoreFileUtility.DerivedKeyEncryptionEntropy.Length);
        Array.Copy((Array) RoamingStoreFileUtility.DerivedKeySignatureEntropy, 0, (Array) buffer2, 0, RoamingStoreFileUtility.DerivedKeySignatureEntropy.Length);
        Array.Copy((Array) numArray, 0, (Array) buffer1, RoamingStoreFileUtility.DerivedKeyEncryptionEntropy.Length, 32);
        Array.Copy((Array) numArray, 0, (Array) buffer2, RoamingStoreFileUtility.DerivedKeySignatureEntropy.Length, 32);
        encryptionKey = shA256Managed.ComputeHash(buffer1);
        signatureKey = shA256Managed.ComputeHash(buffer2);
      }
    }

    private static byte[] DoPkcs5(byte[] password, byte[] salt)
    {
      return new PasswordDeriveBytes(password, salt, "SHA256", 1000).GetBytes(32);
    }

    internal static bool CompareSignature(byte[] input, byte[] expected)
    {
      if (input.Length == 0 || input.Length != expected.Length)
        return false;
      for (int index = 0; index < input.Length; ++index)
      {
        if ((int) expected[index] != (int) input[index])
          return false;
      }
      return true;
    }
  }
}
